package cvo.chess.tests.pieces;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.List;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import cvo.chess.client.entities.IGameFacade;
import cvo.chess.client.entities.armies.pieces.Pawn;
import cvo.chess.client.entities.armies.pieces.Queen;
import cvo.chess.client.entities.armies.pieces.Rook;
import cvo.chess.client.entities.chessboard.ChessboardCoordinate;
import cvo.chess.client.entities.chessboard.IChessboardCoordinate;
import cvo.chess.client.entities.game.Army;
import cvo.chess.client.entities.game.Chessboard;
import cvo.chess.client.entities.game.IPiece;


public class QueenTestPossibleMoves {

	private IGameFacade gf;

	private Chessboard board;
	
	private Army armyWhite;
	
	
	@Before
	public void setUp(){
		gf = mock(IGameFacade.class);		
		
		armyWhite = mock(Army.class);
		when(armyWhite.getColor()).thenReturn("white");
		
		board = mock(Chessboard.class);
		when(board.getHeight()).thenReturn(8);
		when(board.getWidth()).thenReturn(8);
	}
	

	
	@Test
	public void testWhenQueenOnE5() throws Exception{
		IChessboardCoordinate mockCoordinates = mock(IChessboardCoordinate.class);
		when(mockCoordinates.getCol()).thenReturn(4);
		when(mockCoordinates.getRow()).thenReturn(3);
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "E5");
		when(gf.getPieceAt("E5")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinates);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		//*********
		//Includes (clockwise)
		//*********
			
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A5")));		
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B8")));
		
		//*********
		//Excludes (samples)
		//*********
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"A8")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"A7")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"H6")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"A6")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"C2")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"G4")));
		
	}
	

	

	public void testQueenAtH1() throws Exception{
		IChessboardCoordinate mockCoordinates = mock(IChessboardCoordinate.class);
		when(mockCoordinates.getCol()).thenReturn(7);
		when(mockCoordinates.getRow()).thenReturn(7);
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "H1");
		when(gf.getPieceAt("H1")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinates);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		//*********
		//Includes (clockwise)
		//*********
			
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "G1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "G2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H8")));
		
		//*********
		//Excludes (samples)
		//*********
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"G3")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"B8")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"A4")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"E5")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"D2")));
		
	}
	
	public void testQueenAtA1() throws Exception{
		IChessboardCoordinate mockCoordinates = mock(IChessboardCoordinate.class);
		when(mockCoordinates.getCol()).thenReturn(7);
		when(mockCoordinates.getRow()).thenReturn(0);
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "A1");
		when(gf.getPieceAt("A1")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinates);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		//*********
		//Includes (clockwise)
		//*********
			
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H1")));
		
		
		//*********
		//Excludes (samples)
		//*********
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"B3")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"C2")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"H2")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"C5")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"D3")));
				
	}
	
	public void testQueenAtA8() throws Exception{
		IChessboardCoordinate mockCoordinates = mock(IChessboardCoordinate.class);
		when(mockCoordinates.getCol()).thenReturn(0);
		when(mockCoordinates.getRow()).thenReturn(0);
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "A8");
		when(gf.getPieceAt("A8")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinates);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		
		//*********
		//Includes (clockwise)
		//*********
		
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B7")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A7")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A1")));
		
		//*********
		//Excludes (samples)
		//*********
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"C7")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"D6")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"H7")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"D1")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"B3")));
		
		
	}
	
	public void testQueenAtH8() throws Exception{
		IChessboardCoordinate mockCoordinates = mock(IChessboardCoordinate.class);
		when(mockCoordinates.getCol()).thenReturn(7);
		when(mockCoordinates.getRow()).thenReturn(0);
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "H8");
		when(gf.getPieceAt("H8")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinates);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		
		//*********
		//Includes (clockwise)
		//*********
		
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H7")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "G7")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "G8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A8")));
		
		//*********
		//Excludes (samples)
		//*********
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"G6")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"C7")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"A2")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"F1")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"G2")));
	}
	
	
	/**
	 * Tests a scenario where the queen's movements are blocked by an enemy and a friendly
	 * @throws Exception
	 */
	public void testQueenEnemyFriendly() throws Exception{
		//TODO: if a piece is an enemy piece it is a valid position
		Army armyBlack = mock(Army.class);
		when(armyBlack.getColor()).thenReturn("black");
		
	
		
		
		// Create the queen an set at position E5
		IChessboardCoordinate mockCoordinatesQueen = mock(IChessboardCoordinate.class);
		when(mockCoordinatesQueen.getCol()).thenReturn(4);
		when(mockCoordinatesQueen.getRow()).thenReturn(3);		
		IPiece queen = new Queen(gf, armyWhite);
		gf.setPieceAtPosition(queen, "E5");
		when(gf.getPieceAt("E5")).thenReturn(queen);
		when(gf.getPositionOfPiece(queen)).thenReturn(mockCoordinatesQueen);
		
		
		//Create enemy Pawn and sets it at position E7 overlapping queens movements
		IChessboardCoordinate mockCoordinatesEnemy = mock(IChessboardCoordinate.class);
		when(mockCoordinatesEnemy.getCol()).thenReturn(4);
		when(mockCoordinatesEnemy.getRow()).thenReturn(1);		
		IPiece enemyPawn = mock(Pawn.class);		
		when(enemyPawn.getName()).thenReturn("enemyPawn");
		when(enemyPawn.getColor()).thenReturn("black");
		gf.setPieceAtPosition(enemyPawn, "E7");
		when(gf.getPieceAt("E7")).thenReturn(enemyPawn);
		when(gf.getPositionOfPiece(enemyPawn)).thenReturn(mockCoordinatesEnemy);
		
		
		
		
		
		// Create friendly rook and set it at position G5, overlapping queens movements
		IChessboardCoordinate mockCoordinatesFriendly = mock(IChessboardCoordinate.class);
		when(mockCoordinatesEnemy.getCol()).thenReturn(6);
		when(mockCoordinatesEnemy.getRow()).thenReturn(3);		
		IPiece friendlyRook = mock(Rook.class);		
		when(friendlyRook.getName()).thenReturn("friendlyRook");
		when(friendlyRook.getColor()).thenReturn("white");
		gf.setPieceAtPosition(friendlyRook, "G5");
		when(gf.getPieceAt("G5")).thenReturn(friendlyRook);
		when(gf.getPositionOfPiece(friendlyRook)).thenReturn(mockCoordinatesFriendly);
		
		Assert.assertNotNull("List of possible moves may not be null", queen.getPossibleMoves());
		
		Assert.assertFalse("List must contain more possible moves", queen.getPossibleMoves().isEmpty());
		
		List <ChessboardCoordinate> list = queen.getPossibleMoves();
		
		
		//*********
		//Includes (clockwise)
		//*********
		
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E7")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H8")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "F4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "H2")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "E1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D4")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A1")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "A5")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "D6")));
		Assert.assertTrue(list.contains(new ChessboardCoordinate(board, "B8")));
		
		
		//*********
		//Excludes (These are excluded becuase of the placement of the friendly and enemy pieces)
		//*********
		//Enemy Pawn
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"E8")));
		
		//Friendly Rook blocking
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"G5")));
		Assert.assertFalse("May not be included int possMoves", list.contains(new ChessboardCoordinate(board,"H5")));
	}
	

	
	
	
	
	
}
